﻿using System;
using System.Collections.Generic;
using System.Text;
using SchEdu.Framework.Algorithm;
using SchEdu.Framework.Exceptions;
using SchEdu.Framework.DataModel;
using SchEdu.Framework.Validators;

namespace SchEdu.Framework.Algorithm.Rules
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class FAM : Algorithm
    {
        public FAM()
        {
        }

        public FAM(SchEduData schEduData)
            : base(schEduData)
        {
        }

        protected override void InitializeValidators()
        {
            base.InitializeValidators();
            validators.Add(new OrderDueDateValidator(SchEduData));
            validators.Add(new DependencyPerOrderValidator(SchEduData, 0, 0));
        }

        protected override void Logic()
        {

            OperationList nextOperations = OrderOperationSortedList.GetNextOperations();

            time=-1;

            while (nextOperations.Count > 0)
            {
                time++;

                time = Math.Max(time, Machines.GetFirstAvailable().AvailabilityDate);

                MachineList availableMachines = Machines.GetAvailableAt(time);

                if(availableMachines.Count == 0)
                {
                    continue;
                }

                time = Math.Max(time, nextOperations.GetFirstAvailable().AvailabilityDate);

                OperationList availableOperations = nextOperations.GetAvailableAt(time);
                if(availableOperations.Count == 0)
                {
                    continue;
                }

                foreach(SchEduDataSet.MachineRow nextMachine in availableMachines)
                {
                    OperationList possibleOperations = new OperationList();

                    foreach(SchEduDataSet.OperationRow op in availableOperations)
                    {
                        if (nextMachine.WorkCenterID == op.WorkCenterID)
                        {
                            possibleOperations.Add(op);
                        }
                    }

                    if(possibleOperations.Count == 0)
                    {
                        continue;
                    }

                    SchEduDataSet.OperationRow nextOperation = ApplyDispatchRule(time, nextMachine, possibleOperations);

                    nextOperation.StartDate = Math.Max(nextMachine.AvailabilityDate, nextOperation.AvailabilityDate);
                    nextOperation.EndDate = nextOperation.StartDate + nextOperation.ProcessingTime - 1;
                    nextOperation.MachineID = nextMachine.ID;
                    nextMachine.AvailabilityDate = nextOperation.EndDate + 1;

                    OrderOperationSortedList.RemoveByOperation(nextOperation);

                    if (OrderOperationSortedList[nextOperation.OrderRow].Count > 0)
                    {
                        OrderOperationSortedList[nextOperation.OrderRow].Values[0].AvailabilityDate = nextOperation.EndDate + 1;
                    }

                    break;
                }

                nextOperations = OrderOperationSortedList.GetNextOperations();

            }

        }

        protected abstract SchEduDataSet.OperationRow ApplyDispatchRule(int t,SchEduDataSet.MachineRow nextMachine, OperationList nextMachineOperations);


        protected virtual OperationList GetMachineOperationList(SchEduDataSet.MachineRow machine, OperationList nextOperations)
        {
            OperationList machineOperations = new OperationList();

            foreach (SchEduDataSet.OperationRow op in nextOperations)
            {
                if (machine.WorkCenterID == op.WorkCenterID && machine.AvailabilityDate <= op.AvailabilityDate)
                {
                    machineOperations.Add(op);
                }
            }

            return machineOperations;

        }


    }

}
